/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.fzhucc.modules.system.service.impl;

import com.fzhucc.config.FileProperties;
import com.fzhucc.exception.BadRequestException;
import com.fzhucc.exception.EntityExistException;
import com.fzhucc.exception.EntityNotFoundException;
import com.fzhucc.modules.expert.domain.Expert;
import com.fzhucc.modules.expert.repository.ExpertRepository;
import com.fzhucc.modules.lesson.domain.LessonIntegral;
import com.fzhucc.modules.lesson.repository.LessonIntegralRepository;
import com.fzhucc.modules.policy.domain.dto.PolicyMsgBoxQueryCriteria;
import com.fzhucc.modules.security.domain.dto.AuthNewRegistUserDto;
import com.fzhucc.modules.security.domain.dto.AuthRegistUserDto;
import com.fzhucc.modules.security.service.OnlineUserService;
import com.fzhucc.modules.security.service.UserCacheManager;
import com.fzhucc.modules.system.domain.Role;
import com.fzhucc.modules.system.domain.User;
import com.fzhucc.modules.system.domain.UserSmall;
import com.fzhucc.modules.system.domain.dto.UserPhoneWithRandomCodeDto;
import com.fzhucc.modules.system.domain.dto.UserPicNickNameDto;
import com.fzhucc.modules.system.repository.RoleRepository;
import com.fzhucc.modules.system.repository.UserRepository;
import com.fzhucc.modules.system.repository.UserSmallRepository;
import com.fzhucc.modules.system.service.UserService;
import com.fzhucc.modules.system.service.dto.*;
import com.fzhucc.modules.system.service.mapstruct.UserLoginMapper;
import com.fzhucc.modules.system.service.mapstruct.UserMapper;
import com.fzhucc.utils.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Zheng Jie
 * @date 2018-11-23
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {

    private final ExpertRepository expertRepository;

    private final RoleRepository roleRepository;

    private final UserSmallRepository userSmallRepository;

    private final UserRepository userRepository;
    private final UserMapper userMapper;
    private final FileProperties properties;
    private final RedisUtils redisUtils;
    private final UserCacheManager userCacheManager;
    private final OnlineUserService onlineUserService;
    private final UserLoginMapper userLoginMapper;

    private final MsUserService msUserService;

    private final PasswordEncoder passwordEncoder;

    private final LessonIntegralRepository lessonIntegralRepository;

    @Value("${org.area.all}")
    public String all;

    @Override
    public Object queryAll(UserQueryCriteria criteria, Pageable pageable) {
        if (criteria.getOrgArea() != null && !criteria.getOrgArea().equals("")) {
            //h5的直接传orgArea
            if (criteria.getOrgArea().equals(all)) {
                criteria.setOrgArea(null);
            }
        } else {
            //管理端根据登录用户地区
            criteria.setOrgArea(setCriteria(criteria));
        }
        Page<User> page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        Page<UserDto> map = page.map(userMapper::toDto);
        List<UserDto> list = map.getContent();
        if (list != null && list.size() > 0) {
            for (UserDto dto : list) {
                String orgArea = dto.getOrgArea();
                if (orgArea != null && orgArea.contains(";")) {
                    String[] array = orgArea.split(";");
                    dto.setOrgAreas(array);
                } else {
                    String[] array = {};
                    dto.setOrgAreas(array);
                }
            }
        }
        return PageUtil.toPage(map);
    }

    //根据不同设置不同的部门查看 处理  福建省;  或者  福建省;福州市;   或者 福建省;福州市;马尾区; 这种类型
    public String setCriteria(UserQueryCriteria criteria) {
        Long userId = null;
        try {
            userId = SecurityUtils.getCurrentUserId();
        } catch (Exception e) {
            String orgArea = criteria.getOrgArea();
            if (orgArea != null && orgArea.equals(all)) { //如果等于福建省则查全部
                return null;
            } else {
                return orgArea;
            }
        }
        if (userId != null) {
            Optional<User> userOptional = userRepository.findById(userId);
            User res = userOptional.get();
            if (res.getOrgArea() != null && res.getOrgArea().contains(all)) {//包含福建省 则查全部
                return null;
            } else {
                if (res.getOrgArea() == null || res.getOrgArea().equals("")) {
                    //不赋予则返回所有都能看
                    return null;
                }
                if (res.getOrgArea().contains(";")) {
                    String[] split = res.getOrgArea().split(";");
                    if (split.length == 2) {
                        return split[1];
                    } else if (split.length == 3) {
                        return split[1];
                    } else if (split.length == 1) {
                        return split[0];
                    } else {
                        throw new BadRequestException("未符合规范的地区区域");
                    }
                } else {
                    throw new BadRequestException("未符合规范的地区区域");
                }
            }
        } else {
            throw new BadRequestException("用户ID未找到");
        }
    }

    public String orgAreaReturn() {
        Long userId = SecurityUtils.getCurrentUserId();
        if (userId == null) {//未登录则外面传进来
            return "";
        } else {
            Optional<User> userOptional = userRepository.findById(userId);
            User res = userOptional.get();
            return res.getOrgArea();
        }
    }

    @Override
    public List<UserDto> queryAll(UserQueryCriteria criteria) {
        if (criteria.getOrgArea() != null && !criteria.getOrgArea().equals("")) {
            //h5的直接传orgArea
            if (criteria.getOrgArea().equals(all)) {
                criteria.setOrgArea(null);
            }
        } else {
            //管理端根据登录用户地区
            criteria.setOrgArea(setCriteria(criteria));
        }
        List<User> users = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder));
        return userMapper.toDto(users);
    }

    @Override
    @Cacheable(key = "'id:' + #p0")
    @Transactional(rollbackFor = Exception.class)
    public UserDto findById(long id) {
        User user = userRepository.findById(id).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(), "User", "id", id);
        return userMapper.toDto(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(User resources) {
        // TODO 即非福建省用户、则只能根据其部门来赋予
        // 根据用户登录的不同部门 除了福建省部门可以赋予任何的市，则其他则根据它原来登录用户的部门赋予
        String orgarea = orgAreaReturn();
        if (orgarea != null && !orgarea.equals(all)) {
            resources.setOrgArea(orgarea);
        }
        if (userRepository.findByUsername(resources.getUsername()) != null) {
            throw new EntityExistException(User.class, "username", resources.getUsername());
        }
        /*if (userRepository.findByEmail(resources.getEmail()) != null) {
            throw new EntityExistException(User.class, "email", resources.getEmail());
        }*/
        if (userRepository.findByPhone(resources.getPhone()) != null) {
            throw new EntityExistException(User.class, "phone", resources.getPhone());
        }
        //boolean result = expertRepository.existsByPhone(resources.getPhone());
        List<Expert> experts = expertRepository.existsAllByPhoneWithOrgArea(resources.getPhone(), resources.getOrgArea());
        //if (result) {
        if (experts != null && experts.size() == 1) {
            Role expertRole = roleRepository.findByName("专家");
            if (expertRole != null) {
                resources.getRoles().add(expertRole);
            }
        }
        User user = userRepository.save(resources);
        // 更新至认证微服务
        try {
            msUserService.create(user);
        } catch (Exception e) {
        }
    }

    @Override
    public void createWithOrgAreas(UserOrgDto dto) {
        // TODO 即非福建省用户、则只能根据其部门来赋予
        // 根据用户登录的不同部门 除了福建省部门可以赋予任何的市，则其他则根据它原来登录用户的部门赋予
        String[] orgareas = dto.getOrgAreas();
        if (orgareas != null && orgareas.length > 0) {
            String last = "";
            for (String a : orgareas) {
                last = last + a + ";";
            }
            dto.setOrgArea(last);
        } else {
            dto.setOrgArea(orgAreaReturn());
        }

        if (userRepository.findByUsername(dto.getUsername()) != null) {
            throw new EntityExistException(User.class, "username", dto.getUsername());
        }
        /*if (userRepository.findByEmail(resources.getEmail()) != null) {
            throw new EntityExistException(User.class, "email", resources.getEmail());
        }*/
        if (userRepository.findByPhone(dto.getPhone()) != null) {
            throw new EntityExistException(User.class, "phone", dto.getPhone());
        }
        //boolean result = expertRepository.existsByPhone(resources.getPhone());
        List<Expert> experts = expertRepository.existsAllByPhoneWithOrgArea(dto.getPhone(), dto.getOrgArea());
        //if (result) {
        if (experts != null && experts.size() == 1) {
            Role expertRole = roleRepository.findByName("专家");
            if (expertRole != null) {
                dto.getRoles().add(expertRole);
            }
        }

        User resultUser = new User();
        resultUser.setAvatarName(dto.getAvatarName());
        resultUser.setDept(dto.getDept());
        resultUser.setGender(dto.getGender());
        //resultUser.setEmail(dto.getEmail());
        resultUser.setEnabled(dto.getEnabled());
        resultUser.setFen(0);
        resultUser.setIntegral(dto.getIntegral());
        resultUser.setJobs(dto.getJobs());
        resultUser.setOrgArea(dto.getOrgArea());
        resultUser.setPassword(dto.getPassword());
        resultUser.setAvatarPath(dto.getAvatarPath());
        //resultUser.setId(dto.getId());
        resultUser.setNickName(dto.getNickName());
        resultUser.setPhone(dto.getPhone());
        resultUser.setIsAdmin(dto.getIsAdmin());
        resultUser.setProjectLevel(dto.getProjectLevel());
        resultUser.setPwdResetTime(dto.getPwdResetTime());
        resultUser.setUnionId(dto.getUnionId());
        resultUser.setRoles(dto.getRoles());
        resultUser.setType(dto.getType());
        resultUser.setUsername(dto.getUsername());
        resultUser.setCreateBy(dto.getCreateBy());
        resultUser.setIsh5data(dto.getIsh5data());
        resultUser.setUpdateBy(dto.getUpdateBy());
        resultUser.setUpdateTime(dto.getUpdateTime());
        resultUser.setCreateTime(dto.getCreateTime());
        User user = userRepository.save(resultUser);
        // 更新至认证微服务
        try {
            msUserService.create(user);
        } catch (Exception e) {
        }
    }

    @Override
    public void updateProjectLevel(Long userId, int projectLevel) {
        Optional<User> op = userRepository.findById(userId);
        if (op.isEmpty()) {
            throw new BadRequestException("用户不存在");
        }
        User user = op.get();
        user.setProjectLevel(projectLevel);
        userRepository.save(user);
    }

    @Override
    public void updatePhone(Long userId, String phone) {
        Optional<User> op = userRepository.findById(userId);
        if (op.isEmpty()) {
            throw new BadRequestException("用户不存在");
        }
        User user = op.get();
        user.setPhone(phone);
        userRepository.save(user);

        // 更新至认证微服务
        try {
            msUserService.update(user);
        } catch (Exception e) {
        }
        // 清除缓存
        delCaches(user.getId(), user.getUsername());
    }

    @Override
    public void updateMyPhone(String phone) {
        Long userId = SecurityUtils.getCurrentUserId();
        Optional<User> op = userRepository.findById(userId);
        if (!op.isPresent()) {
            throw new BadRequestException("用户不存在");
        }
        User user = op.get();
        user.setPhone(phone);
        userRepository.save(user);

        // 更新至认证微服务
        try {
            msUserService.update(user);
        } catch (Exception e) {
        }
        // 清除缓存
        delCaches(user.getId(), user.getUsername());
    }

    @Override
    public Boolean isPhone() {
        Long userId = SecurityUtils.getCurrentUserId();
        Optional<User> op = userRepository.findById(userId);
        if (!op.isPresent()) {
            throw new BadRequestException("用户不存在");
        }
        User user = op.get();
        if (user.getPhone() == null) {
            return false;
        } else if (user.getPhone().equals("")) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(User resources) throws Exception {
        User user = userRepository.findById(resources.getId()).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(), "User", "id", resources.getId());
        User user1 = userRepository.findByUsername(resources.getUsername());
        User user2 = null;
        User user3 = null;
        /*if (resources.getEmail() != null && !resources.getEmail().equals("")) {
            user2 = userRepository.findByEmail(resources.getEmail());
        }*/
        if (resources.getPhone() != null && !resources.getPhone().equals("")) {
            user3 = userRepository.findByPhone(resources.getPhone());
        }
        if (user1 != null && !user.getId().equals(user1.getId())) {
            throw new EntityExistException(User.class, "username", resources.getUsername());
        }
        /*if (user2 != null && !user.getId().equals(user2.getId())) {
            throw new EntityExistException(User.class, "email", resources.getEmail());
        }*/
        if (user3 != null && !user.getId().equals(user3.getId())) {
            throw new EntityExistException(User.class, "phone", resources.getPhone());
        }
        // 如果用户的角色改变
        if (!resources.getRoles().equals(user.getRoles())) {
            redisUtils.del(CacheKey.DATA_USER + resources.getId());
            redisUtils.del(CacheKey.MENU_USER + resources.getId());
            redisUtils.del(CacheKey.ROLE_AUTH + resources.getId());
        }
        // 修改部门会影响 数据权限
        if (!Objects.equals(resources.getDept(), user.getDept())) {
            redisUtils.del(CacheKey.DATA_USER + resources.getId());
        }
        // 如果用户被禁用，则清除用户登录信息
        if (!resources.getEnabled()) {
            onlineUserService.kickOutForUsername(resources.getUsername());
        }
        //boolean result = expertRepository.existsByPhone(resources.getPhone());
        //if (result) {
        List<Expert> experts = expertRepository.existsAllByPhoneWithOrgArea(resources.getPhone(), resources.getOrgArea());
        if (experts != null && experts.size() == 1) {
            Role expertRole = roleRepository.findByName("专家");
            if (expertRole != null) {
                resources.getRoles().add(expertRole);
            }
        }
        if (!user.getUsername().equals(resources.getUsername())) {
            throw new BadRequestException("非法操作");
        }
        //user.setEmail(resources.getEmail());
        user.setEnabled(resources.getEnabled());
        user.setRoles(resources.getRoles());
        user.setDept(resources.getDept());
        user.setJobs(resources.getJobs());
        //user.setFen(resources.getFen());
        user.setPhone(resources.getPhone());
        user.setIsh5data(resources.getIsh5data());
        user.setNickName(resources.getNickName());
        user.setGender(resources.getGender());

        // TODO 即非福建省用户、则只能根据其部门来赋予
        // 根据用户登录的不同部门 除了福建省部门可以赋予随便，则其他则根据它原来登录用户的部门赋予
        String orgarea = orgAreaReturn();
        if (orgarea != null && !orgarea.equals(all)) {
            user.setOrgArea(orgarea);
        } else {
            user.setOrgArea(resources.getOrgArea());
        }

        user.setType(resources.getType());
        userRepository.save(user);

        // 更新至认证微服务
        try {
            msUserService.update(user);
        } catch (Exception e) {
        }
        // 清除缓存
        delCaches(user.getId(), user.getUsername());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateFen(Long userId, int point) {
        User user = userRepository.findById(userId).orElseGet(User::new);
        int last = 0;
        Integer fen = user.getFen();
        if (fen == null){
            last = point;
        }else{
            last = fen + point;
        }
        user.setFen(last);
        User save = userRepository.save(user);
        // 更新至认证微服务
        try {
            msUserService.update(save);
        } catch (Exception e) {
        }
        // 清除缓存
        delCaches(save.getId(), save.getUsername());
        return save.getFen();
    }

    @Override
    public void updateWithOrgAreas(UserOrgDto dto) throws Exception {
        User user = userRepository.findById(dto.getId()).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(), "User", "id", dto.getId());
        User user1 = userRepository.findByUsername(dto.getUsername());
        User user2 = null;
        User user3 = null;
        /*if (dto.getEmail() != null && !dto.getEmail().equals("")) {
            user2 = userRepository.findByEmail(dto.getEmail());
        }*/
        if (dto.getPhone() != null && !dto.getPhone().equals("")) {
            user3 = userRepository.findByPhone(dto.getPhone());
        }
        if (user1 != null && !user.getId().equals(user1.getId())) {
            throw new EntityExistException(User.class, "username", dto.getUsername());
        }
        /*if (user2 != null && !user.getId().equals(user2.getId())) {
            throw new EntityExistException(User.class, "email", dto.getEmail());
        }*/
        if (user3 != null && !user.getId().equals(user3.getId())) {
            throw new EntityExistException(User.class, "phone", dto.getPhone());
        }
        // 如果用户的角色改变
        if (!dto.getRoles().equals(user.getRoles())) {
            redisUtils.del(CacheKey.DATA_USER + dto.getId());
            redisUtils.del(CacheKey.MENU_USER + dto.getId());
            redisUtils.del(CacheKey.ROLE_AUTH + dto.getId());
        }
        // 修改部门会影响 数据权限
        if (!Objects.equals(dto.getDept(), user.getDept())) {
            redisUtils.del(CacheKey.DATA_USER + dto.getId());
        }
        // 如果用户被禁用，则清除用户登录信息
        if (!dto.getEnabled()) {
            onlineUserService.kickOutForUsername(dto.getUsername());
        }
        //boolean result = expertRepository.existsByPhone(resources.getPhone());
        //if (result) {
        List<Expert> experts = expertRepository.existsAllByPhoneWithOrgArea(dto.getPhone(), dto.getOrgArea());
        if (experts != null && experts.size() == 1) {
            Role expertRole = roleRepository.findByName("专家");
            if (expertRole != null) {
                dto.getRoles().add(expertRole);
            }
        }
        if (!user.getUsername().equals(dto.getUsername())) {
            throw new BadRequestException("非法操作");
        }
        //user.setEmail(dto.getEmail());
        user.setEnabled(dto.getEnabled());
        user.setRoles(dto.getRoles());
        user.setDept(dto.getDept());
        user.setJobs(dto.getJobs());
        user.setPhone(dto.getPhone());
        user.setIsh5data(dto.getIsh5data());
        user.setNickName(dto.getNickName());
        user.setGender(dto.getGender());

        // TODO 外部传进来
        String[] orgareas = dto.getOrgAreas();
        if (orgareas != null && orgareas.length > 0) {
            String last = "";
            for (String a : orgareas) {
                last = last + a + ";";
            }
            user.setOrgArea(last);
        } else {
            user.setOrgArea(orgAreaReturn());
        }

        user.setType(dto.getType());
        userRepository.save(user);

        // 更新至认证微服务
        try {
            msUserService.update(user);
        } catch (Exception e) {
        }
        // 清除缓存
        delCaches(user.getId(), user.getUsername());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateNickname(String username, String nickname) {
        userRepository.updateNickname(username, nickname);
        flushCache(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCenter(User resources) {
        User user = userRepository.findById(resources.getId()).orElseGet(User::new);
        /*User user1 = userRepository.findByPhone(resources.getPhone());
        if (user1 != null && !user.getId().equals(user1.getId())) {
            throw new EntityExistException(User.class, "phone", resources.getPhone());
        }*/
        user.setNickName(resources.getNickName());
        //user.setPhone(resources.getPhone());
        user.setGender(resources.getGender());
        userRepository.save(user);
        // 清理缓存
        delCaches(user.getId(), user.getUsername());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserPhoneBycode(UserPhoneWithRandomCodeDto userPhoneWithRandomCodeDto) {
        String code = userPhoneWithRandomCodeDto.getCode();
        String phone = userPhoneWithRandomCodeDto.getPhone();
        Long userId = SecurityUtils.getCurrentUserId();
        if (userId == null) {
            throw new BadRequestException("用户ID未找到");
        }
        if (phone == null || phone.equals("")) {
            throw new BadRequestException("手机号未找到");
        }
        if (code == null || code.equals("")) {
            throw new BadRequestException("验证码未找到");
        }
        Object res = redisUtils.get(phone);
        if (res == null) {
            throw new BadRequestException("验证码过期");
        }
        String phoneCode = res.toString();
        if (!phoneCode.equals(code)) {
            throw new BadRequestException("验证码不匹配");
        }
        userRepository.updatePhone(phone, userId);
        User user = userRepository.findById(userId).orElseThrow(() ->
                new BadRequestException("用户不存在")
        );

        // 更新至认证微服务
        try {
            msUserService.update(user);
        } catch (Exception e) {
        }
        delCaches(userId, user.username);
    }


    @Override
    public void grantRole(Long userId, Long roleId) {
        User user = userRepository.findById(userId).orElseThrow(() ->
                new BadRequestException("用户不存在")
        );
        Role role = roleRepository.findById(roleId).orElseThrow(() ->
                new BadRequestException("角色不存在")
        );
        user.getRoles().add(role);
        userRepository.save(user);
        flushCache(user.getUsername());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Long> ids) {
        for (Long id : ids) {
            // 清理缓存
            UserDto user = findById(id);
            delCaches(user.getId(), user.getUsername());
        }
        userRepository.deleteAllByIdIn(ids);
    }

    @Override
    public UserDto findByName(String userName) {
        User user = userRepository.findByUsername(userName);
        if (user == null) {
            throw new EntityNotFoundException(User.class, "name", userName);
        } else {
            return userMapper.toDto(user);
        }
    }

    @Override
    public UserDto findsByName(String userName) {
        List<User> lists = userRepository.findListsByUsername(userName);
        if (lists == null) {
            throw new EntityNotFoundException(User.class, "name", userName);
        } else {
            if (lists.size() != 1) {
                if (lists.size() == 0) {
                    throw new BadRequestException("未找到该用户");
                } else {
                    throw new BadRequestException("存在多个用户的情况");
                }
            } else {
                return userMapper.toDto(lists.get(0));
            }
        }
    }

    @Override
    public UserLoginDto getLoginData(String userName) {
        User user = userRepository.findByUsername(userName);
        if (user == null) {
            throw new EntityNotFoundException(User.class, "name", userName);
        } else {
            return userLoginMapper.toDto(user);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePass(String username, String pass) {
        userRepository.updatePass(username, pass, new Date());
        flushCache(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMyUserName(String username, String userId) {
        Optional<User> res = userRepository.findById(Long.parseLong(userId));
        if (!res.isPresent()) {
            throw new BadRequestException("未找到用户");
        }
        userRepository.updateMyUserName(username, Long.parseLong(userId));
        flushCache(res.get().getUsername());
        flushCache(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editNickNameOrAvatar(UserPicNickNameDto dto) {
        Long userId = SecurityUtils.getCurrentUserId();
        Optional<User> op = userRepository.findById(userId);
        if (!op.isPresent()) {
            throw new BadRequestException("用户不存在");
        }
        if (dto.getNickName() != null) {
            userRepository.updateNicknameByUserId(dto.getNickName(), userId);
            flushCache(op.get().getUsername());
        }
        if (dto.getAvatarPath() != null) {
            userRepository.updatePicByUserId(dto.getAvatarPath(), userId);
            flushCache(op.get().getUsername());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void registByCode(AuthRegistUserDto dto) {
        String code = dto.getCode();
        String phone = dto.getPhone();
        String username = dto.getUsername();
        String orgArea = dto.getOrgArea();
        if (username == null || username.equals("")) {
            throw new BadRequestException("用户名未填写");
        }
        if (orgArea == null || orgArea.equals("")) {
            throw new BadRequestException("地区未选择");
        }
        List<UserSmall> alls = userSmallRepository.findAllsByUserName(username, orgArea);
        if (alls != null && alls.size() > 1) {
            throw new BadRequestException("已存在此用户名,请修改注册");
        }
        String pas = dto.getPassword();
        if (pas == null || pas.equals("")) {
            throw new BadRequestException("密码未填写");
        }
        String pwd = passwordEncoder.encode(pas);

        if (phone == null || phone.equals("")) {
            throw new BadRequestException("手机号未找到");
        }
        if (code == null || code.equals("")) {
            throw new BadRequestException("验证码未找到");
        }
        Object res = redisUtils.get("reg" + phone);
        if (res == null) {
            throw new BadRequestException("验证码过期");
        }
        String redisCode = res.toString();
        if (!redisCode.equals(code)) {
            throw new BadRequestException("验证码不匹配");
        }
        //注册账号
        User result = new User();
        result.setUsername(username);
        result.setPassword(pwd);
        result.setIsAdmin(false);
        result.setPhone(phone);
        result.setFen(0);
        result.setNickName(username);
        result.setEnabled(true);
        result.setType(Long.parseLong("3"));
        result.setOrgArea(dto.getOrgArea());//地区org
        result.setPwdResetTime(new Date());
        /*Role resRole = roleRepository.findByName("普通用户");
        if (resRole != null) {
            result.getRoles().add(resRole);
        }*/
        if (result.getType() != null) {
            Optional<Role> ops = roleRepository.findById(result.getType());
            if (ops.isPresent()) {
                Role role = ops.get();
                Set<Role> roles = new HashSet<Role>();
                roles.add(role);
                result.setRoles(roles);
            }
        }
        User user = userRepository.save(result);
        // 更新至认证微服务
        try {
            msUserService.create(user);
        } catch (Exception e) {
        }

    }

    @Override
    public void registNewByCode(AuthNewRegistUserDto dto) {
        String code = dto.getCode();
        String phone = dto.getPhone();
        if (phone == null || phone.equals("")) {
            throw new BadRequestException("未找到手机号");
        }
        List<UserSmall> alls = userSmallRepository.findAllsByPhoneWithOutArea(phone);
        if (alls != null && alls.size() > 1) {
            throw new BadRequestException("已存在此账号,无法注册");
        }
        String pas = dto.getPassword();
        if (pas == null || pas.equals("")) {
            throw new BadRequestException("密码未填写");
        }
        String pwd = passwordEncoder.encode(pas);

        if (code == null || code.equals("")) {
            throw new BadRequestException("验证码未找到");
        }
        Object res = redisUtils.get("regnew" + phone);
        if (res == null) {
            throw new BadRequestException("验证码过期");
        }
        String redisCode = res.toString();
        if (!redisCode.equals(code)) {
            throw new BadRequestException("验证码不匹配");
        }
        String h5Area = null;
        String orgArea = dto.getOrgArea(); //地区area
        if (orgArea != null && !orgArea.equals("")) {
            h5Area = "福建省;" + orgArea + ";";
        }

        //拼上 福建省;xxx;


        //注册账号
        User result = new User();
        result.setUsername(phone);
        result.setPassword(pwd);
        result.setIsAdmin(false);
        result.setPhone(phone);
        result.setNickName(phone);
        result.setEnabled(true);
        result.setFen(0);
        result.setH5area(h5Area);
        result.setType(Long.parseLong("3"));
        //result.setOrgArea(dto.getOrgArea());//地区org
        result.setPwdResetTime(new Date());


        if (result.getType() != null) {
            Optional<Role> ops = roleRepository.findById(result.getType());
            if (ops.isPresent()) {
                Role role = ops.get();
                Set<Role> roles = new HashSet<Role>();
                roles.add(role);
                result.setRoles(roles);
            }
        }
        User user = userRepository.save(result);
        // 更新至认证微服务
        try {
            msUserService.create(user);
        } catch (Exception e) {
        }
    }

    @Override
    public UserDto getMyInfo() {
        Long userId = SecurityUtils.getCurrentUserId();
        Optional<User> op = userRepository.findById(userId);
        if (!op.isPresent()) {
            throw new BadRequestException("用户不存在");
        }
        User user = op.get();
        return userMapper.toDto(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> updateAvatar(File file) {
        // 文件大小验证
        FileUtil.checkSize(properties.getAvatarMaxSize(), file.length());
        // 验证文件上传的格式
        String image = "gif jpg png jpeg";
        String fileType = FileUtil.getExtensionName(file.getName());
        if (fileType != null && !image.contains(fileType)) {
            throw new BadRequestException("文件格式错误！, 仅支持 " + image + " 格式");
        }
        User user = userRepository.findByUsername(JwtSecurityUtils.getCurrentUsername());
        String oldPath = user.getAvatarPath();
        File dest = FileUtil.upload(file, properties.getPath().getAvatar());
        user.setAvatarPath(Objects.requireNonNull(dest).getPath());
        user.setAvatarName(dest.getName());
        userRepository.save(user);
        if (StringUtils.isNotBlank(oldPath)) {
            FileUtil.del(oldPath);
        }
        @NotBlank String username = user.getUsername();
        flushCache(username);
        return new HashMap<>(1) {{
            put("avatar", dest.getName());
        }};
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateEmail(String username, String email) {
        //userRepository.updateEmail(username, email);
        flushCache(username);
    }

    @Override
    public void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (UserDto userDTO : queryAll) {
            List<String> roles = userDTO.getRoles().stream().map(RoleSmallDto::getName).collect(Collectors.toList());
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("用户名", userDTO.getUsername());
            map.put("角色", roles);
            if (userDTO.getDept() == null) {
                map.put("部门", "");
            } else {
                map.put("部门", userDTO.getDept().getName());
            }
            if (userDTO.getJobs() == null) {
                map.put("岗位", "");
            } else {
                map.put("岗位", userDTO.getJobs().stream().map(JobSmallDto::getName).collect(Collectors.toList()));
            }
            map.put("邮箱", userDTO.getEmail());
            map.put("状态", userDTO.getEnabled() ? "启用" : "禁用");
            map.put("手机号码", userDTO.getPhone());
            map.put("修改密码的时间", userDTO.getPwdResetTime());
            map.put("创建日期", userDTO.getCreateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    /**
     * 清理缓存
     *
     * @param id /
     */
    public void delCaches(Long id, String username) {
        redisUtils.del(CacheKey.USER_ID + id);
        flushCache(username);
    }

    /**
     * 清理 登陆时 用户缓存信息
     *
     * @param username /
     */
    private void flushCache(String username) {
        userCacheManager.cleanUserCache(username);
    }

    @Override
    public Object queryAllWithIntegral(UserQueryCriteria criteria, Pageable pageable) {
        Page<User> page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        Page<UserDto> map = page.map(userMapper::toDto);
        List<UserDto> list = map.getContent();
        for (UserDto userDto : list) {
            LessonIntegral lessonIntegral = lessonIntegralRepository.findByUserId(userDto.getId());
            if (lessonIntegral != null) {
                userDto.setIntegral(lessonIntegral.getIntegral());
                userDto.setRemarks(lessonIntegral.getRemarks());
            }
        }
        return PageUtil.toPage(map);
    }

    @Override
    public void updateIntegral(Long userId, Integer integral) {
        Optional<User> op = userRepository.findById(userId);
        if (!op.isPresent()) {
            throw new BadRequestException("用户不存在");
        }
        User user = op.get();
        user.setIntegral(integral);
        userRepository.save(user);
        // 清除缓存
        delCaches(user.getId(), user.getUsername());
    }

    @Override
    public boolean isUserSeeAllCity() {
        Long userId = SecurityUtils.getCurrentUserId();
        Optional<User> op = userRepository.findById(userId);
        if (!op.isPresent()) {
            throw new BadRequestException("用户不存在");
        }
        User user = op.get();
        String orgArea = user.getOrgArea();
        if (orgArea != null && orgArea.equals(all)) {
            return true;
        } else {
            //如果为管理员 也返回true
            Boolean isAdmin = user.getIsAdmin();
            if (isAdmin) {
                return true;
            }
            return false;
        }
    }
}
